package com.github.common.extend.demo.config.json.fastjson.precision;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.github.common.extend.demo.config.json.DecimalPrecision;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * @author wangjj7
 * @date 2022/7/25
 * @description
 */
public class DecimalPrecisionSerializer extends JsonSerializer<Object> implements ContextualSerializer {

    /**
     * 保留的小数精度
     */
    private int decimalPrecision = 2;

    private RoundingMode roundingMode = RoundingMode.HALF_UP;

    public DecimalPrecisionSerializer() {
    }

    public DecimalPrecisionSerializer(int decimalPrecision ,RoundingMode roundingMode) {
        this.decimalPrecision = decimalPrecision;
        this.roundingMode = roundingMode;
    }

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (value == null){
            gen.writeNull();
        }
        Class<?> valueClass = value.getClass();
        if (String.class == valueClass){
            String str = (String) value;
            try {
                gen.writeNumber(new BigDecimal(Double.valueOf(str))
                        .setScale(decimalPrecision ,roundingMode)
                        .doubleValue());
            } catch (NumberFormatException e){
                gen.writeString(str);
            }
        }else if (Double.class == valueClass || double.class == valueClass){
            gen.writeNumber(new BigDecimal((double) value)
                    .setScale(decimalPrecision ,roundingMode)
                    .doubleValue());
        }else if (Float.class == valueClass || float.class == valueClass){
            gen.writeNumber(new BigDecimal((float) value)
                    .setScale(decimalPrecision ,roundingMode)
                    .floatValue());
        }else {
            throw new IllegalStateException("unsupported type");
        }
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        if (beanProperty == null) {
            return serializerProvider.findNullValueSerializer(beanProperty);
        }
        Class<?> beanPropertyType = beanProperty.getType().getRawClass();
        if (beanPropertyType == Double.class || beanPropertyType == Float.class || beanPropertyType == String.class) {
            DecimalPrecision decimalPrecision = beanProperty.getAnnotation(DecimalPrecision.class);
            if (decimalPrecision == null) {
                decimalPrecision = beanProperty.getContextAnnotation(DecimalPrecision.class);
            }
            if (decimalPrecision != null) {
                return new DecimalPrecisionSerializer(decimalPrecision.value() ,decimalPrecision.roundingMode());
            }
        }
        return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
    }

}
